package com.zhongwang.mms.module.material.service;

import com.zhongwang.mms.gen.entity.*;
import com.zhongwang.mms.gen.mapper.BReportPlanMapper;
import com.zhongwang.mms.module.basic.dao.MMaterialDictionaryDao;
import com.zhongwang.mms.module.basic.dao.MMaterialsDao;
import com.zhongwang.mms.module.basic.service.BoardService;
import com.zhongwang.mms.module.material.dao.*;
import com.zhongwang.mms.module.material.model.ComplexStorageModel;
import com.zhongwang.mms.module.material.model.ImportItyToProModel;
import com.zhongwang.mms.module.material.model.MInventoryProjectMarkModel;
import com.zhongwang.mms.module.material.model.MProCodeQueryModel;
import com.zhongwang.mms.module.overview.model.ProjectStatusModel;
import com.zhongwang.mms.module.system.log.LogService;
import com.zhongwang.mms.util.BigDecimalUtils;
import com.zhongwang.mms.util.FileUtils;
import com.zhongwang.mms.util.ShiroUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

import static com.zhongwang.mms.util.PoiUtils.getValue;
import static com.zhongwang.mms.util.StringUtils.isNumber;

/**
 * @Description: 库存划项目 服务层
 * @Author: China.wsg
 * @Date: 2020/04/21 19:43
 */
@Service
public class MItyToProService {

    @Autowired
    private ComplexStorageService complexStorageService;
    @Autowired
    private LogService logService;
    @Autowired
    private MImportMarkErrorDao importMarkErrorDao;
    @Autowired
    private MInventoryDao inventoryDao;
    @Autowired
    private MInventoryProjectMarkDao inventoryProjectMarkDao;
    @Autowired
    private MMaterialsDao materialsDao;
    @Autowired
    private MMaterialDictionaryDao materialDictionaryDao;
    @Autowired
    private MInventoryService inventoryService;
    @Autowired
    private MProjectInventoryMarkDao projectInventoryMarkDao;
    @Autowired
    private MMarkRelationDao markRelationDao;
    @Autowired
    private BReportPlanMapper reportPlanMapper;
    @Autowired
    private MOrderDetailDao orderDetailDao;
    @Autowired
    private BoardService boardService;

    @Value("${user.upload.path}")
    private String uploadPath;

    /**
     * 导出待标记库存在库
     *
     * @param response
     */
    public void inventoryExport(HttpServletResponse response, ComplexStorageModel complexStorageModel) {

        complexStorageModel.setItyAvaWeightZeroFlg(2);  // 可用重量是否为零 1=是 2=否
        complexStorageModel.setItyInType(1);    // 库存类型 1：库存在库 2：项目在库
        List<ComplexStorageModel> model = complexStorageService.findStorage(complexStorageModel, null, null, null,null);

        // 创建HSSFWorkbook对象(excel的文档对象)
        HSSFWorkbook wb = new HSSFWorkbook();
        // 建立新的sheet对象（excel的表单）
        HSSFSheet hssfSheet = wb.createSheet("sheet1");
        // 在sheet里创建第一行，参数为行索引(excel的行)，可以是0～65535之间的任何一个
        HSSFRow hssfRow = hssfSheet.createRow(0);
        // 创建单元格（excel的单元格，参数为列索引，可以是0～255之间的任何一个
        HSSFCell hssfCell = hssfRow.createCell(0);
        // 合并单元格CellRangeAddress构造参数依次表示起始行，截至行，起始列， 截至列
        hssfSheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 14));

        // 设置单元格内容
        hssfCell.setCellValue("导出库存在库" + DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
        hssfRow = hssfSheet.createRow(1);

        hssfRow.createCell(0).setCellValue("库存ID（禁改）");
        hssfRow.createCell(1).setCellValue("原料ID（禁改）");
        hssfRow.createCell(2).setCellValue("类型（禁改）");
        hssfRow.createCell(3).setCellValue("材质（禁改）");
        hssfRow.createCell(4).setCellValue("规格（禁改）");
        hssfRow.createCell(5).setCellValue("宽度（禁改）");
        hssfRow.createCell(6).setCellValue("长度（禁改）");
        hssfRow.createCell(7).setCellValue("米重/厚度（禁改）");
        hssfRow.createCell(8).setCellValue("特殊说明（禁改）");
        hssfRow.createCell(9).setCellValue("数量（禁改）");
        hssfRow.createCell(10).setCellValue("理论重量（禁改）");
        hssfRow.createCell(11).setCellValue("库位（禁改）");
        hssfRow.createCell(12).setCellValue("物料描述（必填）");
        hssfRow.createCell(13).setCellValue("数量 kg（必填）");
        hssfRow.createCell(14).setCellValue("备注");
        hssfRow.createCell(15).setCellValue("项目编号（必填）");
        hssfRow.createCell(16).setCellValue("项目名称（必填）");

        // 在sheet里创建第二行
        for (int i = 0; i < model.size(); i++) {
            HSSFRow row = hssfSheet.createRow(i + 2);
            row.createCell(0).setCellValue(model.get(i).getItyId());
            row.createCell(1).setCellValue(model.get(i).getMatId());
            row.createCell(2).setCellValue(model.get(i).getMatTypeName());
            row.createCell(3).setCellValue(model.get(i).getMatQualityName());
            row.createCell(4).setCellValue(model.get(i).getMatSpecName());
            row.createCell(5).setCellValue(model.get(i).getMatWidth() == null ? "" : String.valueOf(model.get(i).getMatWidth()));
            row.createCell(6).setCellValue(model.get(i).getMatLength() == null ? "" : String.valueOf(model.get(i).getMatLength()));
            row.createCell(7).setCellValue(model.get(i).getMatHeight() == null ? "" : String.valueOf(model.get(i).getMatHeight()));
            row.createCell(8).setCellValue(model.get(i).getItySpec());
            row.createCell(9).setCellValue(Double.parseDouble(String.valueOf(model.get(i).getItyAvaNum())));
            row.createCell(10).setCellValue(Double.parseDouble(String.valueOf(model.get(i).getItyAvaWeight())));
            row.createCell(11).setCellValue(model.get(i).getWhiName());
            row.createCell(12).setCellValue("");
            row.createCell(13).setCellValue("");
            row.createCell(14).setCellValue("");
            row.createCell(15).setCellValue("");
            row.createCell(16).setCellValue("");
        }
        //输出Excel文件
        try {
            OutputStream output = response.getOutputStream();
            response.reset();
            response.setHeader("Content-disposition", "attachment; filename=stockDetails.xls");
            response.setContentType("application/msexcel");
            wb.write(output);
            output.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 库存划项目excel导入执行
     *新导入文件，已数量算重量（202511月，原材料梁原反馈，由于产品类型原因，不能再用数量换算重量公式）
     * @param file 导入文件
     * @return JsonResult
     */
//    @Transactional
//    public String importFile(MultipartFile file) {
//
//        String fileName = file.getOriginalFilename();
//        MInventoryProjectMark inventoryProjectMark;
//        // 错误数据
//        List<MImportMarkError> errorList = new ArrayList<>();
//        int importCount = 0;    // 导入成功记录数
//
//        Workbook workbook = null;
//        try {
//
//            // 判断文件是2007版本还是2010版本
//            InputStream is = file.getInputStream();
//            if (fileName.endsWith("xlsx")) {
//                workbook = new XSSFWorkbook(is);
//            }
//            if (fileName.endsWith("xls")) {
//                workbook = new HSSFWorkbook(is);
//            }
//            if (workbook != null) {
//                //默认读取第一个sheet
//                Sheet sheet = workbook.getSheetAt(0);
//                ImportItyToProModel importItyToProModel;
//                MImportMarkError importMarkError;
//                // 排除标题行，从第二行开始导入
//                for (int i = sheet.getFirstRowNum() + 2; i <= sheet.getLastRowNum(); i++) {
//
//                    Row row = sheet.getRow(i);
//                    // 如果行为空忽略
//                    if (row == null) {
//                        continue;
//                    }
//                    // 如果标记内容什么都没填则忽略该行(物料描述、数量kg、备注、项目编号、项目名称+联系人)
//                    if (StringUtils.isEmpty(getValue(row.getCell(12))) && StringUtils.isEmpty(getValue(row.getCell(13)))
//                            && StringUtils.isEmpty(getValue(row.getCell(14))) && StringUtils.isEmpty(getValue(row.getCell(15)))
//                            && StringUtils.isEmpty(getValue(row.getCell(16)))) {
//                        continue;
//                    }
//                    importItyToProModel = new ImportItyToProModel();
//                    importMarkError = new MImportMarkError();
//                    importItyToProModel.setItyId(getValue(row.getCell(0)));
//                    importItyToProModel.setMatId(getValue(row.getCell(1)));
//                    importItyToProModel.setMatTypeName(getValue(row.getCell(2)));
//                    importItyToProModel.setMatQualityName(getValue(row.getCell(3)));
//                    importItyToProModel.setMatSpecName(getValue(row.getCell(4)));
//                    importItyToProModel.setMatWidth(getValue(row.getCell(5)));
//                    importItyToProModel.setMatLength(getValue(row.getCell(6)));
//                    importItyToProModel.setMatHeight(getValue(row.getCell(7)));
//                    importItyToProModel.setItySpec(getValue(row.getCell(8)));
//                    importItyToProModel.setItyAvaNum(getValue(row.getCell(9)));
//                    importItyToProModel.setItyAvaWeight(getValue(row.getCell(10)));
//                    importItyToProModel.setWhiName(getValue(row.getCell(11)));
//                    importItyToProModel.setMatNameDesc(getValue(row.getCell(12)));
//                    // 目的：标记重量如果带公式，系统崩溃，该条数据之后的数据到不进去，还不提示
//                    Cell cell = row.getCell(13);
//                    cell.setCellType(CellType.STRING);
//                    importItyToProModel.setNeedNum(getValue(cell));
//
//                    importItyToProModel.setRemark(getValue(row.getCell(14)));
//                    importItyToProModel.setMarkProjectCode(getValue(row.getCell(15)));
//                    importItyToProModel.setMarkProjectName(getValue(row.getCell(16)));
//
//                    // 判断 主要禁改字段是否为空
//                    if (importItyToProModel.getItyId() == null || importItyToProModel.getMatId() == null) {
//                        importMarkError.setImeErrorReason("禁改字段被修改");
//                        importMarkError = setImportMarkError(importMarkError, importItyToProModel);
//                        errorList.add(importMarkError);
//                        importMarkErrorDao.insert(importMarkError);
//                        continue;
//                    }
//
//                    // 取得库存在库
//                    MInventory inventory = inventoryDao.selectByPrimaryKey(Integer.valueOf(importItyToProModel.getItyId()));
//
//                    // 判断 主要禁改字段是否被修改
//                    if (importItyToProModel.getItyId() == null || inventory == null || !importItyToProModel.getItyId().equals(String.valueOf(inventory.getItyId()))) {
//                        importMarkError.setImeErrorReason("禁改字段被修改");
//                        importMarkError = setImportMarkError(importMarkError, importItyToProModel);
//                        errorList.add(importMarkError);
//                        importMarkErrorDao.insert(importMarkError);
//                        continue;
//                    }
//                    // 判断 导入Excel必填字段是否填写，不填不允许导入
//                    if (StringUtils.isEmpty(importItyToProModel.getMatNameDesc()) || StringUtils.isEmpty(importItyToProModel.getNeedNum())
//                            || StringUtils.isEmpty(importItyToProModel.getMarkProjectCode()) || StringUtils.isEmpty(importItyToProModel.getMarkProjectName())) {
//                        importMarkError.setImeErrorReason("必填字段为空");
//                        importMarkError = setImportMarkError(importMarkError, importItyToProModel);
//                        errorList.add(importMarkError);
//                        importMarkErrorDao.insert(importMarkError);
//                        continue;
//                    }
//                    //判断 数量kg 字段是否为数字格式
//                    if (!isNumber(importItyToProModel.getNeedNum())) {
//                        importMarkError.setImeErrorReason("[数量]字段应该为数字格式，不应含有英文或汉字");
//                        importMarkError = setImportMarkError(importMarkError, importItyToProModel);
//                        errorList.add(importMarkError);
//                        importMarkErrorDao.insert(importMarkError);
//                        continue;
//                    }
//                    // 判断 项目编码6位字符，如果是8位或者其他位数 则不允许导入
//                    if (importItyToProModel.getMarkProjectCode().length() != 6 && importItyToProModel.getMarkProjectCode().length() != 8) {
//                        importMarkError.setImeErrorReason("[项目编号（必填）]字段应该为6位或8位字符串，例如：18K001、2018K001");
//                        importMarkError = setImportMarkError(importMarkError, importItyToProModel);
//                        errorList.add(importMarkError);
//                        importMarkErrorDao.insert(importMarkError);
//                        continue;
//                    }
//
//                    // 判断 项目编码在看板系统是否存在
//                    MProCodeQueryModel proCodeQueryModel = new MProCodeQueryModel();
//                    proCodeQueryModel.setProCode(boardService.projectCodeHandle(importItyToProModel.getMarkProjectCode()));
//                    List<ProjectStatusModel> projectStatusModels = orderDetailDao.findProjectByCode(proCodeQueryModel);
//                    if (projectStatusModels == null || projectStatusModels.size() == 0) {
//                        importMarkError.setImeErrorReason("[项目编号（必填）]输入的项目编号不存在");
//                        importMarkError = setImportMarkError(importMarkError, importItyToProModel);
//                        errorList.add(importMarkError);
//                        importMarkErrorDao.insert(importMarkError);
//                        continue;
//                    }
//
//                    /*根据 需求重量、可用重量、理论数量、理论重量、实际标记重量
//                    根据计算公式反推 理论数量、理论重量
//                    理论数量：保留小数点后一位，向上取
//                    理论重量：保留两位小数*/
//
//                    // 逻辑1 if（需求数量>可用数量） To errorList
//                    // 逻辑2 if(需求数量 = 可用数量) then 实际标记重量 = 需求重量
//                    // 逻辑3 否则根据 需求重量 计算出 理论数量和理论重量
//                    //       3.1 if(理论数量=可用数量) then 实际标记重量 = 可用重量
//                    //       3.2 if(理论重量<=可用重量) then 实际标记重量 = 理论重量
//                    //       3.3 if(理论重量>可用重量) then 实际标记重量 = 可用重量
//                    // 逻辑1
//                    if (Double.valueOf(importItyToProModel.getNeedNum()) > Double.valueOf(inventory.getItyAvaNum())) {
//                        importMarkError.setImeItyAvaNum(String.valueOf(inventory.getItyAvaNum()));
//                        importMarkError.setImeItyAvaWeight(String.valueOf(inventory.getItyAvaWeight()));
//                        importMarkError.setImeErrorReason("标记数量大于库存可用重量");
//                        importMarkError = setImportMarkError(importMarkError, importItyToProModel);
//                        errorList.add(importMarkError);
//                        importMarkErrorDao.insert(importMarkError);
//                        continue;
//                    }
//                    // 逻辑2
//                    if (Double.valueOf(importItyToProModel.getNeedNum()).equals(Double.valueOf(inventory.getItyAvaNum()))) {
//                        importItyToProModel.setMarkNum(inventory.getItyAvaNum());
//                        importItyToProModel.setMarkWeight(inventory.getItyAvaWeight());
//                    } else {
//                        // 逻辑3
//                        importItyToProModel = setMarkNumAndWeight(importItyToProModel, inventory);
//                    }
//
//                    // 插入标记表
//                    inventoryProjectMark = new MInventoryProjectMark();
//                    inventoryProjectMark.setIpmBeforeItyId(inventory.getItyId());
//                    inventoryProjectMark.setIpmNum(importItyToProModel.getMarkNum());
//                    inventoryProjectMark.setIpmWeight(importItyToProModel.getMarkWeight());
//                    inventoryProjectMark.setIpmDate(new Date());
//                    inventoryProjectMark.setIpmProposer(ShiroUtils.getUser().getName());
//                    inventoryProjectMark.setIpmInProjectCode(boardService.projectCodeHandle(importItyToProModel.getMarkProjectCode()));
//                    inventoryProjectMark.setIpmInProjectName(importItyToProModel.getMarkProjectName());
//                    inventoryProjectMark.setIpmRemark(importItyToProModel.getRemark());
//                    inventoryProjectMark.setIpmAppStatus(1); //标记状态：0=删除 1=未提交 2=已提交 3=执行
//                    inventoryProjectMark.setIpmAccount(ShiroUtils.getLoginName());
//                    inventoryProjectMark.setIpmNameDescExcel(importItyToProModel.getMatNameDesc());
////                    inventoryProjectMark.setIpmWeightExcel(Double.valueOf(importItyToProModel.getNeedWeight()));
//                    inventoryProjectMark.setIpmNumExcel(Double.valueOf(importItyToProModel.getNeedNum()));
//                    inventoryProjectMark.setIpmPrice(inventory.getItyPrice());
//                    inventoryProjectMarkDao.insert(inventoryProjectMark);
//
//                    // 更新库存表可用数量及重量
//                    inventory.setItyAvaNum(BigDecimalUtils.sub(inventory.getItyAvaNum(), importItyToProModel.getMarkNum()));
//                    inventory.setItyAvaWeight(BigDecimalUtils.sub(inventory.getItyAvaWeight(), importItyToProModel.getMarkWeight()));
//                    inventoryDao.updateByPrimaryKeySelective(inventory);
//
//                    importCount++;
//                }
//
//                logService.saveLog("库存划项目标记导入", "导入成功：" + importCount + "条， " + "导入失败：" + errorList.size() + "条");
//                return errorList.size() > 0 ? "导入失败" : "导入完成";
//            } else {
//                return "导入失败";
//            }
//
//        } catch (Exception e) {
//            e.printStackTrace();
//        } finally {
//            if (workbook != null) {
//                try {
//                    workbook.close();
//                } catch (Exception ignored) {
//                }
//            }
//        }
//        return "导入失败";
//    }
    /**
     * 库存划项目excel导入执行
     *原导入文件已重量算数量，由于怕改回来，方法没变后边加1备用
     * @param file 导入文件
     * @return JsonResult
     */
    @Transactional
    public String importFile1(MultipartFile file) {

        String fileName = file.getOriginalFilename();
        MInventoryProjectMark inventoryProjectMark;
        // 错误数据
        List<MImportMarkError> errorList = new ArrayList<>();
        int importCount = 0;    // 导入成功记录数

        Workbook workbook = null;
        try {

            // 判断文件是2007版本还是2010版本
            InputStream is = file.getInputStream();
            if (fileName.endsWith("xlsx")) {
                workbook = new XSSFWorkbook(is);
            }
            if (fileName.endsWith("xls")) {
                workbook = new HSSFWorkbook(is);
            }
            if (workbook != null) {
                //默认读取第一个sheet
                Sheet sheet = workbook.getSheetAt(0);
                ImportItyToProModel importItyToProModel;
                MImportMarkError importMarkError;
                // 排除标题行，从第二行开始导入
                for (int i = sheet.getFirstRowNum() + 2; i <= sheet.getLastRowNum(); i++) {

                    Row row = sheet.getRow(i);
                    // 如果行为空忽略
                    if (row == null) {
                        continue;
                    }
                    // 如果标记内容什么都没填则忽略该行(物料描述、数量kg、备注、项目编号、项目名称+联系人)
                    if (StringUtils.isEmpty(getValue(row.getCell(12))) && StringUtils.isEmpty(getValue(row.getCell(13)))
                            && StringUtils.isEmpty(getValue(row.getCell(14))) && StringUtils.isEmpty(getValue(row.getCell(15)))
                            && StringUtils.isEmpty(getValue(row.getCell(16)))) {
                        continue;
                    }
                    importItyToProModel = new ImportItyToProModel();
                    importMarkError = new MImportMarkError();
                    importItyToProModel.setItyId(getValue(row.getCell(0)));
                    importItyToProModel.setMatId(getValue(row.getCell(1)));
                    importItyToProModel.setMatTypeName(getValue(row.getCell(2)));
                    importItyToProModel.setMatQualityName(getValue(row.getCell(3)));
                    importItyToProModel.setMatSpecName(getValue(row.getCell(4)));
                    importItyToProModel.setMatWidth(getValue(row.getCell(5)));
                    importItyToProModel.setMatLength(getValue(row.getCell(6)));
                    importItyToProModel.setMatHeight(getValue(row.getCell(7)));
                    importItyToProModel.setItySpec(getValue(row.getCell(8)));
                    importItyToProModel.setItyAvaNum(getValue(row.getCell(9)));
                    importItyToProModel.setItyAvaWeight(getValue(row.getCell(10)));
                    importItyToProModel.setWhiName(getValue(row.getCell(11)));
                    importItyToProModel.setMatNameDesc(getValue(row.getCell(12)));
                    // 目的：标记重量如果带公式，系统崩溃，该条数据之后的数据到不进去，还不提示
                    Cell cell = row.getCell(13);
                    cell.setCellType(CellType.STRING);
                    importItyToProModel.setNeedWeight(getValue(cell));

                    importItyToProModel.setRemark(getValue(row.getCell(14)));
                    importItyToProModel.setMarkProjectCode(getValue(row.getCell(15)));
                    importItyToProModel.setMarkProjectName(getValue(row.getCell(16)));

                    // 判断 主要禁改字段是否为空
                    if (importItyToProModel.getItyId() == null || importItyToProModel.getMatId() == null) {
                        importMarkError.setImeErrorReason("禁改字段被修改");
                        importMarkError = setImportMarkError(importMarkError, importItyToProModel);
                        errorList.add(importMarkError);
                        importMarkErrorDao.insert(importMarkError);
                        continue;
                    }

                    // 取得库存在库
                    MInventory inventory = inventoryDao.selectByPrimaryKey(Integer.valueOf(importItyToProModel.getItyId()));

                    // 判断 主要禁改字段是否被修改
                    if (importItyToProModel.getItyId() == null || inventory == null || !importItyToProModel.getItyId().equals(String.valueOf(inventory.getItyId()))) {
                        importMarkError.setImeErrorReason("禁改字段被修改");
                        importMarkError = setImportMarkError(importMarkError, importItyToProModel);
                        errorList.add(importMarkError);
                        importMarkErrorDao.insert(importMarkError);
                        continue;
                    }
                    // 判断 导入Excel必填字段是否填写，不填不允许导入
                    if (StringUtils.isEmpty(importItyToProModel.getMatNameDesc()) || StringUtils.isEmpty(importItyToProModel.getNeedWeight())
                            || StringUtils.isEmpty(importItyToProModel.getMarkProjectCode()) || StringUtils.isEmpty(importItyToProModel.getMarkProjectName())) {
                        importMarkError.setImeErrorReason("必填字段为空");
                        importMarkError = setImportMarkError(importMarkError, importItyToProModel);
                        errorList.add(importMarkError);
                        importMarkErrorDao.insert(importMarkError);
                        continue;
                    }
                    //判断 数量kg 字段是否为数字格式
                    if (!isNumber(importItyToProModel.getNeedWeight())) {
                        importMarkError.setImeErrorReason("[数量kg]字段应该为数字格式，不应含有英文或汉字");
                        importMarkError = setImportMarkError(importMarkError, importItyToProModel);
                        errorList.add(importMarkError);
                        importMarkErrorDao.insert(importMarkError);
                        continue;
                    }
                    // 判断 项目编码6位字符，如果是8位或者其他位数 则不允许导入
                    if (importItyToProModel.getMarkProjectCode().length() != 6 && importItyToProModel.getMarkProjectCode().length() != 8) {
                        importMarkError.setImeErrorReason("[项目编号（必填）]字段应该为6位或8位字符串，例如：18K001、2018K001");
                        importMarkError = setImportMarkError(importMarkError, importItyToProModel);
                        errorList.add(importMarkError);
                        importMarkErrorDao.insert(importMarkError);
                        continue;
                    }

                    // 判断 项目编码在看板系统是否存在
                    MProCodeQueryModel proCodeQueryModel = new MProCodeQueryModel();
                    proCodeQueryModel.setProCode(boardService.projectCodeHandle(importItyToProModel.getMarkProjectCode()));
                    List<ProjectStatusModel> projectStatusModels = orderDetailDao.findProjectByCode(proCodeQueryModel);
                    if (projectStatusModels == null || projectStatusModels.size() == 0) {
                        importMarkError.setImeErrorReason("[项目编号（必填）]输入的项目编号不存在");
                        importMarkError = setImportMarkError(importMarkError, importItyToProModel);
                        errorList.add(importMarkError);
                        importMarkErrorDao.insert(importMarkError);
                        continue;
                    }

                    /*根据 需求重量、可用重量、理论数量、理论重量、实际标记重量
                    根据计算公式反推 理论数量、理论重量
                    理论数量：保留小数点后一位，向上取
                    理论重量：保留两位小数*/

                    // 逻辑1 if（需求重量>可用重量） To errorList
                    // 逻辑2 if(需求重量 = 可用重量) then 实际标记重量 = 需求重量
                    // 逻辑3 否则根据 需求重量 计算出 理论数量和理论重量
                    //       3.1 if(理论数量=可用数量) then 实际标记重量 = 可用重量
                    //       3.2 if(理论重量<=可用重量) then 实际标记重量 = 理论重量
                    //       3.3 if(理论重量>可用重量) then 实际标记重量 = 可用重量
                    // 逻辑1
                    if (Double.valueOf(importItyToProModel.getNeedWeight()) > Double.valueOf(inventory.getItyAvaWeight())) {
                        importMarkError.setImeItyAvaNum(String.valueOf(inventory.getItyAvaNum()));
                        importMarkError.setImeItyAvaWeight(String.valueOf(inventory.getItyAvaWeight()));
                        importMarkError.setImeErrorReason("标记重量大于库存可用重量");
                        importMarkError = setImportMarkError(importMarkError, importItyToProModel);
                        errorList.add(importMarkError);
                        importMarkErrorDao.insert(importMarkError);
                        continue;
                    }
                    // 逻辑2
                    if (Double.valueOf(importItyToProModel.getNeedWeight()).equals(Double.valueOf(inventory.getItyAvaWeight()))) {
                        importItyToProModel.setMarkNum(inventory.getItyAvaNum());
                        importItyToProModel.setMarkWeight(inventory.getItyAvaWeight());
                    } else {
                        // 逻辑3
                        importItyToProModel = setMarkNumAndWeight1(importItyToProModel, inventory);
                    }

                    // 插入标记表
                    inventoryProjectMark = new MInventoryProjectMark();
                    inventoryProjectMark.setIpmBeforeItyId(inventory.getItyId());
                    inventoryProjectMark.setIpmNum(importItyToProModel.getMarkNum());
                    inventoryProjectMark.setIpmWeight(importItyToProModel.getMarkWeight());
                    inventoryProjectMark.setIpmDate(new Date());
                    inventoryProjectMark.setIpmProposer(ShiroUtils.getUser().getName());
                    inventoryProjectMark.setIpmInProjectCode(boardService.projectCodeHandle(importItyToProModel.getMarkProjectCode()));
                    inventoryProjectMark.setIpmInProjectName(importItyToProModel.getMarkProjectName());
                    inventoryProjectMark.setIpmRemark(importItyToProModel.getRemark());
                    inventoryProjectMark.setIpmAppStatus(1); //标记状态：0=删除 1=未提交 2=已提交 3=执行
                    inventoryProjectMark.setIpmAccount(ShiroUtils.getLoginName());
                    inventoryProjectMark.setIpmNameDescExcel(importItyToProModel.getMatNameDesc());
                    inventoryProjectMark.setIpmWeightExcel(Double.valueOf(importItyToProModel.getNeedWeight()));
                    inventoryProjectMark.setIpmPrice(inventory.getItyPrice());
                    inventoryProjectMarkDao.insert(inventoryProjectMark);

                    // 更新库存表可用数量及重量
                    inventory.setItyAvaNum(BigDecimalUtils.sub(inventory.getItyAvaNum(), importItyToProModel.getMarkNum()));
                    inventory.setItyAvaWeight(BigDecimalUtils.sub(inventory.getItyAvaWeight(), importItyToProModel.getMarkWeight()));
                    inventoryDao.updateByPrimaryKeySelective(inventory);

                    importCount++;
                }

                logService.saveLog("库存划项目标记导入", "导入成功：" + importCount + "条， " + "导入失败：" + errorList.size() + "条");
                return errorList.size() > 0 ? "导入失败" : "导入完成";
            } else {
                return "导入失败";
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (workbook != null) {
                try {
                    workbook.close();
                } catch (Exception ignored) {
                }
            }
        }
        return "导入失败";
    }

    /**
     * 导入异常数据赋值
     *
     * @param importMarkError
     * @param importMarkModel
     * @return
     */
    private MImportMarkError setImportMarkError(MImportMarkError importMarkError, ImportItyToProModel importMarkModel) {

        importMarkError.setImeItyId(importMarkModel.getItyId());
        importMarkError.setImeMatId(importMarkModel.getMatId());
        importMarkError.setImeMatTypeName(importMarkModel.getMatTypeName());
        importMarkError.setImeMatQualityName(importMarkModel.getMatQualityName());
        importMarkError.setImeMatSpecName(importMarkModel.getMatSpecName());
        importMarkError.setImeMatWidth(importMarkModel.getMatWidth());
        importMarkError.setImeMatLength(importMarkModel.getMatLength());
        importMarkError.setImeMatHeight(importMarkModel.getMatHeight());
        importMarkError.setImeItySpec(importMarkModel.getItySpec());
        importMarkError.setImeItyAvaNum(importMarkModel.getItyAvaNum());
        importMarkError.setImeItyAvaWeight(importMarkModel.getItyAvaWeight());
        importMarkError.setImeMatNameDesc(importMarkModel.getMatNameDesc());
        importMarkError.setImeNeedWeight(importMarkModel.getNeedWeight());
        importMarkError.setImeNeedNum(importMarkModel.getNeedNum());
        importMarkError.setImeRemark(importMarkModel.getRemark());
        importMarkError.setImeMarkProCode(importMarkModel.getMarkProjectCode());
        importMarkError.setImeMarkProName(importMarkModel.getMarkProjectName());
        importMarkError.setImeUserName(ShiroUtils.getLoginName());
        importMarkError.setImeMarkUser(ShiroUtils.getUser().getName());
        importMarkError.setImeMarkDate(new Date());

        return importMarkError;
    }

    /**
     * 根据 需求重量 计算出 理论数量和理论重量
     *新方法，数量换算重量（202511月，原材料梁原反馈，由于产品类型原因，不能再用数量换算重量公式）
     * @param importMarkModel
     * @param inventory
     * @return
     */
//    private ImportItyToProModel setMarkNumAndWeight(ImportItyToProModel importMarkModel, MInventory inventory) {
//
//        Double theoryNum = 0.0;     // 理论数量
//        Double theoryWeight = 0.0;  // 理论重量
////        Double needWeight = Double.valueOf(importMarkModel.getNeedNum());
//        Double needNum = Double.valueOf(importMarkModel.getNeedNum());
//        // 取得物料规格
//        MMaterials materials = materialsDao.selectByPrimaryKey(inventory.getItyMatId());
//        MMaterialDictionary materialDictionary = materialDictionaryDao.selectByPrimaryKey(materials.getMatSpecId());
//
//        Double spec = isNumber(materialDictionary.getMdName()) ? Double.valueOf(materialDictionary.getMdName()) : 0.0;       // 规格
//        Double width = materials.getMatWidth() == null ? 0.0 : materials.getMatWidth();      // 宽度
//        Double length = materials.getMatLength() == null ? 0.0 : materials.getMatLength();      // 长度
//        Double height = materials.getMatHeight() == null ? 0.0 : materials.getMatHeight();      // 厚度
//        Integer formulaType = materials.getMatFormulaType();
//
//        if (formulaType == null) {
//            // 没有公式，原料科手动更新数量和重量字段
//            theoryNum = needNum;
//        } else if (formulaType == 1) {
//            // 重量 =（规格*宽度*长度*数量*7.85/1000）-（(规格-2*米重/厚度)*（宽度-2*米重/厚度）*7.85/1000*数量*长度）
//            theoryWeight = formatRound((spec * width * length * needNum * 7.85 / 1000) - ((spec - 2 * height) * (width - 2 * height) * 7.85 / 1000 * needNum * length));
//            // 数量 = 重量/[（规格*宽度*长度*7.85/1000）-(规格-2*米重/厚度)*（宽度-2*米重/厚度）*7.85/1000*长度）]
//            theoryNum = formatRoundUp(theoryWeight / ((spec * width * length * 7.85 / 1000) - (spec - 2 * height) * (width - 2 * height) * 7.85 / 1000 * length));
//
//        } else if (formulaType == 2) {
//            // 重量 = 规格*规格*长度*数量*0.00617
//            theoryWeight = formatRound(spec * spec * length * needNum * 0.00617);
//            // 数量 = 重量/（规格*规格*长度*0.00617）
//            theoryNum = formatRoundUp(theoryWeight / (spec * spec * length * 0.00617));
//
//        } else if (formulaType == 3) {
//            // 重量 = 长度*数量*米重/厚度
//            theoryWeight = formatRound(length * needNum * height);
//            // 数量 = 重量/（长度*米厚）
//            theoryNum = formatRoundUp(theoryWeight / (length * height));
//
//        } else if (formulaType == 4) {
//            // 重量 =（规格-宽度）*宽度*0.02466*长度*数量
//            theoryWeight = formatRound((spec - width) * width * 0.02466 * length * needNum);
//            // 数量 = 重量/[（规格-宽度）*宽度*0.02466*长度)]
//            theoryNum = formatRoundUp(theoryWeight / ((spec - width) * width * 0.02466 * length));
//
//        } else if (formulaType == 5) {
//            // 重量 = 规格*宽度*长度*2.7/1000000*数量
//            theoryWeight = formatRound(spec * width * length * 2.7 / 1000000 * needNum);
//            // 数量 = 重量/（规格*宽度*长度*2.7/1000000）
//            theoryNum = formatRoundUp(theoryWeight / (spec * width * length * 2.7 / 1000000));
//
//        } else if (formulaType == 6) {
//            // 重量 = 规格*宽度*长度*7.85/1000000*数量
//            theoryWeight = formatRound(spec * width * length * 7.85 / 1000000 * needNum);
//            // 数量 = 重量/（规格*宽度*长度*7.85/1000000）
//            theoryNum = formatRoundUp(theoryWeight / (spec * width * length * 7.85 / 1000000));
//
//        }
//
//        /*3.1 if(理论数量=可用数量) then 实际标记重量 = 可用重量
//        3.2 if(理论重量<=可用重量) then 实际标记重量 = 理论重量
//        3.3 if(理论重量>可用重量) then 实际标记重量 = 可用重量*/
//        if (theoryNum.compareTo(inventory.getItyAvaNum()) == 0) {
//            importMarkModel.setMarkNum(inventory.getItyAvaNum());
//            importMarkModel.setMarkWeight(inventory.getItyAvaWeight());
//        } else if (theoryWeight <= inventory.getItyAvaWeight()) {
//            importMarkModel.setMarkNum(theoryNum);
//            importMarkModel.setMarkWeight(theoryWeight);
//        } else if (theoryWeight > inventory.getItyAvaWeight()) {
//            importMarkModel.setMarkNum(inventory.getItyAvaNum());
//            importMarkModel.setMarkWeight(inventory.getItyAvaWeight());
//        }
//
//        return importMarkModel;
//    }
    /**
     * 根据 需求重量 计算出 理论数量和理论重量
     *原计算方法，重量换算数量
     * @param importMarkModel
     * @param inventory
     * @return
     */
    private ImportItyToProModel setMarkNumAndWeight1(ImportItyToProModel importMarkModel, MInventory inventory) {

        Double theoryNum = 0.0;     // 理论数量
        Double theoryWeight = 0.0;  // 理论重量
        Double needWeight = Double.valueOf(importMarkModel.getNeedWeight());

        // 取得物料规格
        MMaterials materials = materialsDao.selectByPrimaryKey(inventory.getItyMatId());
        MMaterialDictionary materialDictionary = materialDictionaryDao.selectByPrimaryKey(materials.getMatSpecId());

        Double spec = isNumber(materialDictionary.getMdName()) ? Double.valueOf(materialDictionary.getMdName()) : 0.0;       // 规格
        Double width = materials.getMatWidth() == null ? 0.0 : materials.getMatWidth();      // 宽度
        Double length = materials.getMatLength() == null ? 0.0 : materials.getMatLength();      // 长度
        Double height = materials.getMatHeight() == null ? 0.0 : materials.getMatHeight();      // 厚度
        Integer formulaType = materials.getMatFormulaType();

        if (formulaType == null) {
            // 没有公式，原料科手动更新数量和重量字段
            theoryWeight = needWeight;
        } else if (formulaType == 1) {
            // 数量 = 重量/[（规格*宽度*长度*7.85/1000）-(规格-2*米重/厚度)*（宽度-2*米重/厚度）*7.85/1000*长度）]
            theoryNum = formatRoundUp(needWeight / ((spec * width * length * 7.85 / 1000) - (spec - 2 * height) * (width - 2 * height) * 7.85 / 1000 * length));
            // 重量 =（规格*宽度*长度*数量*7.85/1000）-（(规格-2*米重/厚度)*（宽度-2*米重/厚度）*7.85/1000*数量*长度）
            theoryWeight = formatRound((spec * width * length * theoryNum * 7.85 / 1000) - ((spec - 2 * height) * (width - 2 * height) * 7.85 / 1000 * theoryNum * length));
        } else if (formulaType == 2) {
            // 数量 = 重量/（规格*规格*长度*0.00617）
            theoryNum = formatRoundUp(needWeight / (spec * spec * length * 0.00617));
            // 重量 = 规格*规格*长度*数量*0.00617
            theoryWeight = formatRound(spec * spec * length * theoryNum * 0.00617);
        } else if (formulaType == 3) {
            // 数量 = 重量/（长度*米厚）
            theoryNum = formatRoundUp(needWeight / (length * height));
            // 重量 = 长度*数量*米重/厚度
            theoryWeight = formatRound(length * theoryNum * height);
        } else if (formulaType == 4) {
            // 数量 = 重量/[（规格-宽度）*宽度*0.02466*长度)]
            theoryNum = formatRoundUp(needWeight / ((spec - width) * width * 0.02466 * length));
            // 重量 =（规格-宽度）*宽度*0.02466*长度*数量
            theoryWeight = formatRound((spec - width) * width * 0.02466 * length * theoryNum);
        } else if (formulaType == 5) {
            // 数量 = 重量/（规格*宽度*长度*2.7/1000000）
            theoryNum = formatRoundUp(needWeight / (spec * width * length * 2.7 / 1000000));
            // 重量 = 规格*宽度*长度*2.7/1000000*数量
            theoryWeight = formatRound(spec * width * length * 2.7 / 1000000 * theoryNum);
        } else if (formulaType == 6) {
            // 数量 = 重量/（规格*宽度*长度*7.85/1000000）
            theoryNum = formatRoundUp(needWeight / (spec * width * length * 7.85 / 1000000));
            // 重量 = 规格*宽度*长度*7.85/1000000*数量
            theoryWeight = formatRound(spec * width * length * 7.85 / 1000000 * theoryNum);
        }

        /*3.1 if(理论数量=可用数量) then 实际标记重量 = 可用重量
        3.2 if(理论重量<=可用重量) then 实际标记重量 = 理论重量
        3.3 if(理论重量>可用重量) then 实际标记重量 = 可用重量*/
        if (theoryNum.compareTo(inventory.getItyAvaNum()) == 0) {
            importMarkModel.setMarkNum(inventory.getItyAvaNum());
            importMarkModel.setMarkWeight(inventory.getItyAvaWeight());
        } else if (theoryWeight <= inventory.getItyAvaWeight()) {
            importMarkModel.setMarkNum(theoryNum);
            importMarkModel.setMarkWeight(theoryWeight);
        } else if (theoryWeight > inventory.getItyAvaWeight()) {
            importMarkModel.setMarkNum(inventory.getItyAvaNum());
            importMarkModel.setMarkWeight(inventory.getItyAvaWeight());
        }

        return importMarkModel;
    }

    /**
     * 向上保留2位小数
     *
     * @param d
     * @return
     */
    private double formatRoundUp(Double d) {
        return new BigDecimal(Double.toString(d)).setScale(2, BigDecimal.ROUND_UP).doubleValue();
    }

    /**
     * 保留两位小数，四舍五入的一个老土的方法
     *
     * @param d
     * @return
     */
    public static double formatRound(double d) {
        return (double) Math.round(d * 100) / 100;
    }

    /**
     * 导出标记导入异常Excel（15天之内）
     *
     * @param response
     */
    public void exportErrorExport(HttpServletResponse response) {

        MImportMarkErrorExample ex = new MImportMarkErrorExample();
        ex.setOrderByClause("ime_mark_date desc");
        MImportMarkErrorExample.Criteria criteria = ex.createCriteria();
        criteria.andImeUserNameEqualTo(ShiroUtils.getLoginName());  // 登入账号

        // 查询15天之内的异常数据
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.add(calendar.DAY_OF_MONTH, -15);

        criteria.andImeMarkDateGreaterThanOrEqualTo(calendar.getTime());
        criteria.andImeMarkDateLessThanOrEqualTo(new Date());

        List<MImportMarkError> model = importMarkErrorDao.selectByExample(ex);

        // 创建HSSFWorkbook对象(excel的文档对象)
        HSSFWorkbook wb = new HSSFWorkbook();
        // 建立新的sheet对象（excel的表单）
        HSSFSheet hssfSheet = wb.createSheet("sheet1");
        // 在sheet里创建第一行，参数为行索引(excel的行)，可以是0～65535之间的任何一个
        HSSFRow hssfRow = hssfSheet.createRow(0);
        // 创建单元格（excel的单元格，参数为列索引，可以是0～255之间的任何一个
        HSSFCell hssfCell = hssfRow.createCell(0);
        // 合并单元格CellRangeAddress构造参数依次表示起始行，截至行，起始列， 截至列
        hssfSheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 19));

        // 设置单元格内容
        hssfCell.setCellValue("导出标记异常数据" + DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
        hssfRow = hssfSheet.createRow(1);

        hssfRow.createCell(0).setCellValue("库存ID（禁改）");
        hssfRow.createCell(1).setCellValue("原料ID（禁改）");
        hssfRow.createCell(2).setCellValue("类型（禁改）");
        hssfRow.createCell(3).setCellValue("材质（禁改）");
        hssfRow.createCell(4).setCellValue("规格（禁改）");
        hssfRow.createCell(5).setCellValue("宽度（禁改）");
        hssfRow.createCell(6).setCellValue("长度（禁改）");
        hssfRow.createCell(7).setCellValue("米重/厚度（禁改）");
        hssfRow.createCell(8).setCellValue("特殊说明（禁改）");
        hssfRow.createCell(9).setCellValue("数量（禁改）");
        hssfRow.createCell(10).setCellValue("理论重量（禁改）");
        hssfRow.createCell(11).setCellValue("物料描述（必填）");
        hssfRow.createCell(12).setCellValue("数量（必填）");
        hssfRow.createCell(13).setCellValue("备注");
        hssfRow.createCell(14).setCellValue("项目编号（必填）");
        hssfRow.createCell(15).setCellValue("项目名称（必填）");
        hssfRow.createCell(16).setCellValue("异常原因");
        hssfRow.createCell(17).setCellValue("导入日期");


        // 在sheet里创建第二行
        for (int i = 0; i < model.size(); i++) {
            HSSFRow row = hssfSheet.createRow(i + 2);
            row.createCell(0).setCellValue(model.get(i).getImeItyId());
            row.createCell(1).setCellValue(model.get(i).getImeMatId());
            row.createCell(2).setCellValue(model.get(i).getImeMatTypeName());
            row.createCell(3).setCellValue(model.get(i).getImeMatQualityName());
            row.createCell(4).setCellValue(model.get(i).getImeMatSpecName());
            row.createCell(5).setCellValue(model.get(i).getImeMatWidth());
            row.createCell(6).setCellValue(model.get(i).getImeMatLength());
            row.createCell(7).setCellValue(model.get(i).getImeMatHeight());
            row.createCell(8).setCellValue(model.get(i).getImeItySpec());
            row.createCell(9).setCellValue(String.valueOf(model.get(i).getImeItyAvaNum()));
            row.createCell(10).setCellValue(String.valueOf(model.get(i).getImeItyAvaWeight()));
            row.createCell(11).setCellValue(model.get(i).getImeMatNameDesc());
            row.createCell(12).setCellValue(String.valueOf(model.get(i).getImeNeedNum()));
            row.createCell(13).setCellValue(model.get(i).getImeRemark());
            row.createCell(14).setCellValue(model.get(i).getImeMarkProCode());
            row.createCell(15).setCellValue(model.get(i).getImeMarkProName());
            row.createCell(16).setCellValue(model.get(i).getImeErrorReason());

            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            row.createCell(17).setCellValue(dateFormat.format(model.get(i).getImeMarkDate()));
        }
        //输出Excel文件
        try {
            OutputStream output = response.getOutputStream();
            response.reset();
            response.setHeader("Content-disposition", "attachment; filename=importError.xls");
            response.setContentType("application/msexcel");
            wb.write(output);
            output.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 修改库存划项目标记状态
     *
     * @param inventoryProjectMark 修改信息
     * @return
     */
    @Transactional
    public int updateStatus(MInventoryProjectMark inventoryProjectMark) {

        // 标记记录
        MInventoryProjectMark ityToProMark = inventoryProjectMarkDao.selectByPrimaryKey(inventoryProjectMark.getIpmId());
        logService.saveLog(inventoryProjectMark.getIpmAppStatus() == 0 ? "删除库存划项目标记" : "提交库存划项目标记",
                "标记项目：" + ityToProMark.getIpmInProjectCode() + "  " + ityToProMark.getIpmInProjectName() +
                        "<br> 标记物料：" + ityToProMark.getIpmNameDescExcel() + "<br> 标记重量：" + ityToProMark.getIpmWeightExcel());

        if (inventoryProjectMark.getIpmAppStatus() == 0) {
            // 标记删除：将原料在库可用数量、可用重量增加标记量
            MInventory inventory = inventoryDao.selectByPrimaryKey(ityToProMark.getIpmBeforeItyId());
            inventory.setItyAvaNum(BigDecimalUtils.add(inventory.getItyAvaNum(), ityToProMark.getIpmNum()));
            inventory.setItyAvaWeight(BigDecimalUtils.add(inventory.getItyAvaWeight(), ityToProMark.getIpmWeight()));
            inventoryDao.updateByPrimaryKey(inventory);
        }
        int row = inventoryProjectMarkDao.updateByPrimaryKeySelective(inventoryProjectMark);
        return row;
    }

    /**
     * 批量提交库存划项目标记
     *
     * @param arr 标记Id集合
     * @return
     */
    @Transactional
    public void togetherCommit(List<Integer> arr) {

        MInventoryProjectMark inventoryProjectMark;
        for (int i = 0; i < arr.size(); i++) {
            inventoryProjectMark = new MInventoryProjectMark();
            inventoryProjectMark.setIpmId(arr.get(i));
            inventoryProjectMark.setIpmAppStatus(2);
            inventoryProjectMarkDao.updateByPrimaryKeySelective(inventoryProjectMark);
        }

        logService.saveLog("库存划项目批量提交", "批量提交" + arr.size() + "条");
    }

    /**
     * 保存库存划项目标记
     *
     * @param inventoryProjectMark 保存信息
     * @return json 数据
     */
    @Transactional
    public String save(MInventoryProjectMark inventoryProjectMark) {

        // 判断库存是否充足
        MInventory inventory = inventoryDao.selectByPrimaryKey(inventoryProjectMark.getIpmBeforeItyId());
        double a = inventory.getItyAvaNum();
        double b = inventory.getItyAvaWeight();
        double c = inventoryProjectMark.getIpmNum();
        double d = inventoryProjectMark.getIpmWeight();
        if (a < c || b < d) {
            return "标记量大于可用量";
        }

        // 保存标记记录
        inventoryProjectMark.setIpmDate(new Date());
        inventoryProjectMark.setIpmProposer(ShiroUtils.getUser().getName());
        inventoryProjectMark.setIpmAppStatus(1); //标记状态：0=删除 1=未提交 2=已提交 3=执行
        inventoryProjectMark.setIpmAccount(ShiroUtils.getLoginName());
        inventoryProjectMark.setIpmPrice(inventory.getItyPrice());
        inventoryProjectMark.setIpmInProjectCode(inventoryProjectMark.getIpmInProjectCode().toUpperCase());// 小写转大写
        inventoryProjectMarkDao.insert(inventoryProjectMark);

        // 更新库存表可用数量及重量
        inventory.setItyAvaNum(BigDecimalUtils.sub(inventory.getItyAvaNum(), inventoryProjectMark.getIpmNum()));
        inventory.setItyAvaWeight(BigDecimalUtils.sub(inventory.getItyAvaWeight(), inventoryProjectMark.getIpmWeight()));
        inventoryDao.updateByPrimaryKeySelective(inventory);

        MMaterials materials = materialsDao.selectByPrimaryKey(inventory.getItyMatId());
        logService.saveLog("库存划项目标记", materials.getMatNameDesc() + "<br>标记项目：" + inventoryProjectMark.getIpmInProjectCode()
                + "  " + inventoryProjectMark.getIpmInProjectName()
                + "<br>标记量：" + inventoryProjectMark.getIpmWeight() + "  " + materials.getMatWeightUnit());

        return "";
    }

    /**
     * 修改库存划项目标记
     *
     * @param inventoryProjectMark 保存信息
     * @return json 数据
     */
    @Transactional
    public String edit(MInventoryProjectMark inventoryProjectMark) {

        // 判断库存是否充足
        MInventoryProjectMark oldMark = inventoryProjectMarkDao.selectByPrimaryKey(inventoryProjectMark.getIpmId());
        MInventory inventory = inventoryDao.selectByPrimaryKey(oldMark.getIpmBeforeItyId());
        double a = BigDecimalUtils.add(inventory.getItyAvaNum(), oldMark.getIpmNum());
        double b = BigDecimalUtils.add(inventory.getItyAvaWeight(), oldMark.getIpmWeight());
        double c = inventoryProjectMark.getIpmNum();
        double d = inventoryProjectMark.getIpmWeight();
        if (a < c || b < d) {
            return "标记量大于可用量";
        }

        // 修改标记记录
        inventoryProjectMark.setIpmInProjectCode(inventoryProjectMark.getIpmInProjectCode().toUpperCase()); // 小写转大写
        inventoryProjectMarkDao.updateByPrimaryKeySelective(inventoryProjectMark);

        // 更新库存表可用数量及重量
        inventory.setItyAvaNum(BigDecimalUtils.sub(a, inventoryProjectMark.getIpmNum()));
        inventory.setItyAvaWeight(BigDecimalUtils.sub(b, inventoryProjectMark.getIpmWeight()));
        inventoryDao.updateByPrimaryKeySelective(inventory);

        logService.saveLog("库存划项目标记修改", oldMark, inventoryProjectMark);

        return "";
    }

    /**
     * 库存划项目执行（单条）
     *
     * @param ipmId
     * @return json 数据
     */
    @Transactional
    public String checkSingle(Integer ipmId) {

        String msg = "";  // 返回提示信息
        String errorReason;

        MInventoryProjectMark ityToPro = inventoryProjectMarkDao.selectByPrimaryKey(ipmId);
        MInventory inventory = inventoryDao.selectByPrimaryKey(ityToPro.getIpmBeforeItyId());
        MMaterials materials = materialsDao.selectByPrimaryKey(inventory.getItyMatId());

        // 校验是否满足库存划项目执行条件
        errorReason = checkValidate(ityToPro, inventory);
        if (errorReason.length() == 0) {

            //满足条件 执行操作
            checkMethod(ityToPro, inventory);
        } else {
            msg = msg + errorReason + " <br>库存划项目执行失败";
            return msg;
        }

        logService.saveLog("库存划项目执行", materials.getMatNameDesc() + "<br>标记项目：" + ityToPro.getIpmInProjectCode() + "  " + ityToPro.getIpmInProjectName()
                + "<br>标记量：" + ityToPro.getIpmWeight() + "  " + materials.getMatWeightUnit());
        return "库存划项目执行成功！";

    }

    /**
     * 库存划项目执行（批量）
     *
     * @param arr 明细Id集合
     * @return
     */
    @Transactional
    public String checkTogether(List<Integer> arr) {
        String msg = "";  // 返回提示信息
        String errorReason; // 校验原因
        int errorCount = 0; // 审核失败记录数
        int successCount = 0; // 成功审核记录数
        MInventoryProjectMark ityToPro;
        MInventory inventory;

        for (int i = 0; i < arr.size(); i++) {
            ityToPro = inventoryProjectMarkDao.selectByPrimaryKey(arr.get(i));
            inventory = inventoryDao.selectByPrimaryKey(ityToPro.getIpmBeforeItyId());

            // 校验是否满足库存划项目执行条件
            errorReason = checkValidate(ityToPro, inventory);
            if (errorReason.length() == 0) {

                //满足条件 执行操作
                checkMethod(ityToPro, inventory);
                successCount++;
            } else {
                msg = msg + errorReason;
                errorCount++;
                continue;
            }
        }

        logService.saveLog("库存划项目批量执行", "执行成功：" + successCount + "条, 执行失败：" + errorCount + "条");
        return msg.length() > 0 ? msg + "<br> 以上数据库存划项目执行失败！" : "库存划项目执行成功！";
    }

    /**
     * 库存划项目撤销（单条）
     *
     * @param ipmId
     * @return
     */
    @Transactional
    public String cancelSingle(Integer ipmId) {

        String msg = "";  // 返回提示信息
        String errorReason;

        MInventoryProjectMark ityToPro = inventoryProjectMarkDao.selectByPrimaryKey(ipmId);
        MInventory beforeInventory = inventoryDao.selectByPrimaryKey(ityToPro.getIpmBeforeItyId());
        MInventory afterInventory = inventoryDao.selectByPrimaryKey(ityToPro.getIpmAfterItyId());
        MMaterials materials = materialsDao.selectByPrimaryKey(beforeInventory.getItyMatId());

        // 校验是否满足库存划项目撤销条件
        errorReason = checkCancelValidate(ityToPro, beforeInventory, afterInventory);
        if (errorReason.length() == 0) {

            //满足条件 执行操作
            cancelMethod(ityToPro, beforeInventory, afterInventory);
        } else {
            msg = msg + errorReason + " <br>库存划项目撤销失败";
            return msg;
        }

        logService.saveLog("库存划项目撤销", materials.getMatNameDesc() + "<br>标记项目：" + ityToPro.getIpmInProjectCode() + "  " + ityToPro.getIpmInProjectName()
                + "<br>标记量：" + ityToPro.getIpmWeight() + "  " + materials.getMatWeightUnit());
        return "库存划项目撤销成功！";

    }

    /**
     * 校验是否满足库存划项目执行条件
     *
     * @param inventoryProjectMark 库存划项目记录
     * @param inventory            原料在库
     * @return
     */
    private String checkValidate(MInventoryProjectMark inventoryProjectMark, MInventory inventory) {

        String errorReason = "";
        // 如果已经被执行，不允许二次执行(pim_app_status 0删除 1未提交 2已提交 3执行 4废除)
        // 提示信息：项目号 项目名称 标记重量 失败原因
        if (inventoryProjectMark.getIpmAppStatus() == 3) {

            errorReason = errorReason + "<br>" + inventory.getItyProCode() + "  " + inventory.getItyProName() + "  标记量 " + inventoryProjectMark.getIpmWeight() + "  已经被执行";
        }

        // 判断库存在库量是否充足
        double a = inventory.getItyNum();
        double b = inventory.getItyWeight();
        double c = inventoryProjectMark.getIpmNum();
        double d = inventoryProjectMark.getIpmWeight();
        if (a < c || b < d) {
            errorReason = errorReason + "<br>" + inventory.getItyProCode() + "  " + inventory.getItyProName() + "  标记量 " + inventoryProjectMark.getIpmWeight() + "  库存在库量不足";
        }

        return errorReason;
    }

    /**
     * 库存划项目执行
     *
     * @param ityToPro        标记记录
     * @param beforeInventory 原料在库
     */
    private void checkMethod(MInventoryProjectMark ityToPro, MInventory beforeInventory) {

        // 封装库存在库实体并保存
        MInventory afterInventory = new MInventory();
        afterInventory.setItyMatId(beforeInventory.getItyMatId());
        afterInventory.setItyInType(2);// 项目在库
        afterInventory.setItyProCode(ityToPro.getIpmInProjectCode());
        afterInventory.setItyProName(ityToPro.getIpmInProjectName());
        afterInventory.setItySpec(beforeInventory.getItySpec() == null ? "" : beforeInventory.getItySpec());
        afterInventory.setItyTrackCode(beforeInventory.getItyTrackCode());
        afterInventory.setItyNum(ityToPro.getIpmNum());
        afterInventory.setItyWeight(ityToPro.getIpmWeight());
        afterInventory.setItyAvaNum(ityToPro.getIpmNum());
        afterInventory.setItyAvaWeight(ityToPro.getIpmWeight());

        // 应原料科要求：返料日期 自动填写成'yyyy/MM/dd划'
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
        afterInventory.setItyBackDate(dateFormat.format(ityToPro.getIpmDate()) + "划");

        afterInventory.setItyPrice(ityToPro.getIpmPrice());
        afterInventory.setItyStoId(beforeInventory.getItyStoId());
        afterInventory.setItyMatSapCode(beforeInventory.getItyMatSapCode());
        afterInventory.setSupplier(beforeInventory.getSupplier());
        afterInventory = inventoryService.addInventory(afterInventory, 1);

        // 更新库存划项目表信息
        ityToPro.setIpmAfterItyId(afterInventory.getItyId());
        ityToPro.setIpmAppStatus(3);
        ityToPro.setIpmChekcDate(new Date());
        ityToPro.setIpmExecutor(ShiroUtils.getUser().getName());
        inventoryProjectMarkDao.updateByPrimaryKeySelective(ityToPro);

        // 减少原项目在库量
        inventoryService.subInventory(beforeInventory, ityToPro.getIpmNum(), ityToPro.getIpmWeight(), 0.0, 0.0);

        // 更新库存划项目对应的项目划库存标记等信息
        addMarkRelation(ityToPro, beforeInventory);
    }

    /**
     * 更新库存划项目对应的项目划库存标记等信息
     * 初衷 满足原料需求的两张报表 需求如下：
     * 1、查看项目对应物料的总重量多少，其中总重量中采购量、库存备件使用量、其他项目划库存->库存划到本项目量分别是多少的报表统计
     * 2、与上一张报表相反。查看项目划库存的物料都被哪些项目消耗掉了，分别的消耗重量是多少。
     *
     * @param ityToPro
     */
    private void addMarkRelation(MInventoryProjectMark ityToPro, MInventory beforeInventory) {

        MMarkRelation markRelation; // 库存划项目与项目划库存关系记录
        MProjectInventoryMark projectInventoryMark; // 项目划库存

        // 查询项目划库存记录(查询条件：物料id，根据执行时间 升序排列)
        MProjectInventoryMarkExample ex = new MProjectInventoryMarkExample();
        ex.setOrderByClause("pim_chekc_date asc");
        MProjectInventoryMarkExample.Criteria criteria = ex.createCriteria();
        criteria.andPimMatIdEqualTo(beforeInventory.getItyMatId());  // 物料id
        criteria.andPimAppStatusEqualTo(3);
        criteria.andPimResidueWeightGreaterThan(0.0);   // 未被使用量
        List<MProjectInventoryMark> model = projectInventoryMarkDao.selectByExample(ex);

        Double lackWeight = ityToPro.getIpmWeight();    // 库存划项目未被分配量
        Double usedWeight = 0.0;    // 单条标记量
        if (model != null && model.size() > 0) {
            for (int i = 0; i < model.size(); i++) {
                if (lackWeight.compareTo(model.get(i).getPimResidueWeight()) <= 0) {
                    usedWeight = lackWeight;
                    lackWeight = 0.0;
                } else {
                    usedWeight = model.get(i).getPimResidueWeight();
                    lackWeight = BigDecimalUtils.sub(lackWeight, usedWeight);
                }

                // 插入标记对应关系表
                markRelation = new MMarkRelation();
                markRelation.setMrtIpmId(ityToPro.getIpmId());
                markRelation.setMrtPimId(model.get(i).getPimId());
                markRelation.setMrtWeight(usedWeight);
                markRelation.setMrtStatus(1);
                markRelation.setMrtDate(new Date());
                markRelation.setMrtUser(ShiroUtils.getUser().getName());
                markRelationDao.insert(markRelation);

                // 更新项目划库存标记表占用数量
                projectInventoryMark = new MProjectInventoryMark();
                projectInventoryMark.setPimId(model.get(i).getPimId());
                projectInventoryMark.setPimUsedWeight(BigDecimalUtils.add(model.get(i).getPimUsedWeight() == null ? 0.0 : model.get(i).getPimUsedWeight(), usedWeight));
                projectInventoryMarkDao.updateByPrimaryKeySelective(projectInventoryMark);

                if (lackWeight.compareTo(0.0) <= 0) {
                    return;
                }
            }
        }
    }

    /**
     * 校验是否满足库存划项目撤销条件
     *
     * @param inventoryProjectMark 库存划项目记录
     * @param beforeInventory      标记前原料在库
     * @param afterInventory       执行后对应原料在库
     * @return
     */
    private String checkCancelValidate(MInventoryProjectMark inventoryProjectMark, MInventory beforeInventory, MInventory afterInventory) {

        String errorReason = "";
        // 如果已经被执行，不允许二次执行(pim_app_status 0删除 1未提交 2已提交 3执行 4废除)
        // 提示信息：项目号 项目名称 标记重量 失败原因
        if (inventoryProjectMark.getIpmAppStatus() != 3) {

            errorReason = errorReason + "<br>" + inventoryProjectMark.getIpmInProjectCode() + "  " + inventoryProjectMark.getIpmInProjectName() + "  标记量 " + inventoryProjectMark.getIpmWeight() + "  已经被撤销";
        }

        // 判断库存在库量是否充足
        double a = afterInventory.getItyAvaNum();
        double b = afterInventory.getItyAvaWeight();
        double c = inventoryProjectMark.getIpmNum();
        double d = inventoryProjectMark.getIpmWeight();
        if (a < c || b < d) {
            errorReason = errorReason + "<br>" + inventoryProjectMark.getIpmInProjectCode() + "  " + inventoryProjectMark.getIpmInProjectName() + "  标记量 " + inventoryProjectMark.getIpmWeight() + "  已被使用";
        }

        return errorReason;
    }

    /**
     * 库存划项目撤销
     *
     * @param ityToPro        库存划项目记录
     * @param beforeInventory 标记前原料在库
     * @param afterInventory  执行后对应原料在库
     */
    private void cancelMethod(MInventoryProjectMark ityToPro, MInventory beforeInventory, MInventory afterInventory) {

        // 更改提报计划表状态
        if (ityToPro.getIpmRppId() != null) {
            BReportPlan reportPlan = new BReportPlan();
            reportPlan.setRppId(ityToPro.getIpmRppId());
            reportPlan.setRppIsFlag(0); // 是否选择库存标志 0=否 1=是
            reportPlanMapper.updateByPrimaryKeySelective(reportPlan);
        }

        // 减少执行后对应原料在库
        inventoryService.subInventory(afterInventory, ityToPro.getIpmNum(), ityToPro.getIpmWeight(), ityToPro.getIpmNum(), ityToPro.getIpmWeight());

        // 更新项目划库存表信息
        ityToPro.setIpmAfterItyId(null);
        ityToPro.setIpmAppStatus(2);
        ityToPro.setIpmChekcDate(null);
        ityToPro.setIpmExecutor(null);
        ityToPro.setIpmRppId(null);
        inventoryProjectMarkDao.updateByPrimaryKey(ityToPro);

        // 增加标记前原料在库
        beforeInventory.setItyNum(BigDecimalUtils.add(beforeInventory.getItyNum(), ityToPro.getIpmNum()));
        beforeInventory.setItyWeight(BigDecimalUtils.add(beforeInventory.getItyWeight(), ityToPro.getIpmWeight()));
        inventoryDao.updateByPrimaryKeySelective(beforeInventory);

        // 清空库存划项目对应的项目划库存标记等信息
        subMarkRelation(ityToPro);

    }

    /**
     * 清空库存划项目对应的项目划库存标记等信息
     *
     * @param ityToPro 库存划项目记录
     */
    private void subMarkRelation(MInventoryProjectMark ityToPro) {

        MProjectInventoryMark projectInventoryMark; // 项目划库存
        MMarkRelation markRelation;

        MMarkRelationExample ex = new MMarkRelationExample();
        MMarkRelationExample.Criteria criteria = ex.createCriteria();
        criteria.andMrtIpmIdEqualTo(ityToPro.getIpmId());  // 库存划项目id
        criteria.andMrtStatusEqualTo(1);  // 未删除
        List<MMarkRelation> model = markRelationDao.selectByExample(ex);

        if (model != null && model.size() > 0) {

            for (int i = 0; i < model.size(); i++) {

                // 更新项目划库存标记表占用数量
                projectInventoryMark = projectInventoryMarkDao.selectByPrimaryKey(model.get(i).getMrtPimId());
                projectInventoryMark.setPimUsedWeight(BigDecimalUtils.sub(projectInventoryMark.getPimUsedWeight(), model.get(i).getMrtWeight()));
                projectInventoryMarkDao.updateByPrimaryKeySelective(projectInventoryMark);

                // 删除标记对应关系表记录
                markRelation = new MMarkRelation();
                markRelation.setMrtId(model.get(i).getMrtId());
                markRelation.setMrtStatus(0);
                markRelation.setMrtDelDate(new Date());
                markRelation.setMrtDelUser(ShiroUtils.getUser().getName());
                markRelationDao.updateByPrimaryKeySelective(markRelation);
            }

        }
    }

    /**
     * 列表 导出
     *
     * @param inventoryProjectMarkModel 查询条件
     * @return list
     */
    public void exportExcel(HttpServletResponse response, MInventoryProjectMarkModel inventoryProjectMarkModel) {
        List<MInventoryProjectMarkModel> list = inventoryProjectMarkDao.findMarkListByQuery(inventoryProjectMarkModel);
        User user = (User) SecurityUtils.getSubject().getPrincipal();
        logService.saveLog("库存划项目标记记录——导出","用户:【"+user.getName()+"】执行导出操作！");
        String path = uploadPath + user.getAccount() + "/";
        FileUtils.export(path, "库存划项目列表.xls", MInventoryProjectMarkModel.class, "sheet1", list, response);
    }


}
